/*
 * @Author: wuqingchun
 * @Date: 2024-04-25 09:06:23
 * @Description: CPU 缓存对程序性能影响测试程序
 * @LastEditors: wuqingchun
 * @LastEditTime: 2024-04-26 11:29:59
 */
#ifndef __PERF_CPU_CACHE_H__
#define __PERF_CPU_CACHE_H__

#include <thread>
#include <string.h>

#include "perf_time.h"
#include "perf_affinity.h"

struct Point
{
    int iX;
    int iY;
};

struct PointPadding
{
    int iX;
    char cPadding[60];
    int iY;
};

class PerfCPUCache
{
private:
    
public:
    static void CheckCacheLineSize(int iStep)
    {
        const int ARRAY_SIZE = 64 * 1024 * 1024;
        int* piData = new int[ARRAY_SIZE];
        // 提前对内存进行初始化，避免“缺页异常对测试结果的影响”
        (void)memset(piData, 0, ARRAY_SIZE * sizeof(int));

        uint64_t uiStart = PerfTime::GetClockTime();
        for (int i = 0; i < ARRAY_SIZE; i += iStep)
        {
            piData[i] *= 3;
        }

        uint64_t uiEnd = PerfTime::GetClockTime();

        std::cout << "  Step: " << iStep << std::endl
                  << "CostNS: " << uiEnd - uiStart << std::endl;
    }

    template <typename TPOINT>
    static void TestFalseSharing()
    {
        uint64_t uiStart = PerfTime::GetClockTime();
        
        TPOINT stPoint;
        std::thread objX([&stPoint](TPOINT* pstPoint){
            // 线程绑核，屏蔽线程抢占的对测试结果的影响
            PerfAffinity::SetThreadAffinity(1);

            for (int i = 0; i < 100000000; i++)
            {
                //stPoint.iX += 1;
                pstPoint->iX += 1;
            }
        }, &stPoint);

        std::thread objY([&stPoint](TPOINT* pstPoint){
            // 线程绑核，屏蔽线程抢占的对测试结果的影响
            PerfAffinity::SetThreadAffinity(2);
            for (int i = 0; i < 100000000; i++)
            {
                //stPoint.iY += 1;
                pstPoint->iY += 1;
            }
        }, &stPoint);

        objX.join();
        objY.join();

        uint64_t uiEnd = PerfTime::GetClockTime();

        std::cout <<"CostNS: " << uiEnd - uiStart << std::endl;
    }

    /**
     * @brief 逐行遍历数组
     * 
     */
    static int rowTraversal()
    {
        const int ROW = 1024;
        const int COLUMN = 1024;
        int aiMatrix[ROW][COLUMN];
        int iSum = 0;

        uint64_t uiStart = PerfTime::GetClockTime();
        for (int row = 0; row < ROW; row++)
        {
            for (int col = 0; col < COLUMN; col++)
            {
                iSum += aiMatrix[row][col];
            }
        }
        
        uint64_t uiEnd = PerfTime::GetClockTime();

        std::cout <<"CostNS: " << uiEnd - uiStart << std::endl;

        return iSum;
    }

    /**
     * @brief 逐列遍历数组
     * 
     */
    static int ColumnTraversal()
    {
        const int ROW = 1024;
        const int COLUMN = 1024;
        int aiMatrix[ROW][COLUMN];
        int iSum = 0;

        uint64_t uiStart = PerfTime::GetClockTime();
        
        for (int col = 0; col < COLUMN; col++)
        {
            for (int row = 0; row < ROW; row++)
            {
                iSum += aiMatrix[row][col];
            }
        }

        uint64_t uiEnd = PerfTime::GetClockTime();

        std::cout <<"CostNS: " << uiEnd - uiStart << std::endl;

        return iSum;
    }

    static void UpdateCounter()
    {
        int aiCounter[1024] = {};

        uint64_t uiStart = PerfTime::GetClockTime();

        std::thread objT1([&aiCounter](int iPos){
            PerfAffinity::SetThreadAffinity(1);
            for (int j = 0; j < 100000000; j++)
            {
                aiCounter[iPos] = aiCounter[iPos] + 3;
            }
        }, 16);

        std::thread objT2([&aiCounter](int iPos){
            PerfAffinity::SetThreadAffinity(2);
            for (int j = 0; j < 100000000; j++)
            {
                aiCounter[iPos] = aiCounter[iPos] + 3;
            }
        }, 32);

        objT1.join();
        objT2.join();

        uint64_t uiEnd = PerfTime::GetClockTime();

        std::cout <<"CostNS: " << uiEnd - uiStart << std::endl;
    }

    // 指令级并行
    static void InstructionParallelism()
    {
        int aiCouter[2] = {0};
        const int EXEC_TIMES = 256 * 1024 * 1024;

        uint64_t uiStart = PerfTime::GetClockTime();
        for (int i = 0; i < EXEC_TIMES; i++)
        {
            aiCouter[0]++;
            aiCouter[0]++;
        }

        uint64_t uiEnd = PerfTime::GetClockTime();

        std::cout <<"CostNS: " << uiEnd - uiStart << std::endl;
    }

    // 指令级并行
    static void InstructionParallelism2()
    {
        int aiCouter[2] = {0};
        const int EXEC_TIMES = 256 * 1024 * 1024;

        uint64_t uiStart = PerfTime::GetClockTime();
        for (int i = 0; i < EXEC_TIMES; i++)
        {
            aiCouter[0]++;
            aiCouter[1]++;
        }
        uint64_t uiEnd = PerfTime::GetClockTime();
        std::cout <<"CostNS: " << uiEnd - uiStart << std::endl;
    }
};

#endif //__PERF_CPU_CACHE_H__